package com.hospital.workstation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.hospital.common.core.domain.R;
import com.hospital.common.core.domain.entity.SysUser;
import com.hospital.common.core.domain.model.LoginUser;
import com.hospital.common.helper.LoginHelper;
import com.hospital.common.utils.StringUtils;
import com.hospital.common.core.page.TableDataInfo;
import com.hospital.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hospital.system.mapper.SysUserMapper;
import com.hospital.workstation.constant.DictConstants;
import com.hospital.workstation.domain.*;
import com.hospital.workstation.domain.bo.MedicalRecordBo;
import com.hospital.workstation.domain.bo.TraditionalDiagnosisBo;
import com.hospital.workstation.domain.vo.HisAdmittingDiagInfoVo;
import com.hospital.workstation.domain.vo.MedicalRecordVo;
import com.hospital.workstation.domain.vo.TraditionalDiagnosisVo;
import com.hospital.workstation.mapper.*;
import com.hospital.workstation.utils.PoiTlUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import com.hospital.workstation.domain.bo.MedicationSummaryBo;
import com.hospital.workstation.domain.vo.MedicationSummaryVo;
import com.hospital.workstation.service.IMedicationSummaryService;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 药历小结信息Service业务层处理
 *
 * @author hospital
 * @date 2023-02-16
 */
@RequiredArgsConstructor
@Service
public class MedicationSummaryServiceImpl implements IMedicationSummaryService {

    private final MedicationSummaryMapper baseMapper;
    private final TraditionalDiagnosisMapper traditionalDiagnosisMapper;
    private final MedicalRecordMapper medicalRecordMapper;
    private final PatientBaseInfoMapper patientBaseInfoMapper;
    private final SysUserMapper userMapper;
    // 中医诊断数据填充列表
    List<Map<String, Object>> traditionalDiagnosisList = null;
    // 住院期间药物治疗汇总数据填充列表
    List<Map<String, Object>> medicalRecordList = null;
    // 中药饮片填充列表
    List<Map<String, Object>> traditionalMedicalList = null;
    private final HisAdmittingDiagInfoMapper diagInfoMapper;

    /**
     * 查询药历小结信息
     */
    @Override
    public MedicationSummaryVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询药历小结信息列表
     */
    @Override
    public TableDataInfo<MedicationSummaryVo> queryPageList(MedicationSummaryBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<MedicationSummary> lqw = buildQueryWrapper(bo);
        Page<MedicationSummaryVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询药历小结信息列表
     */
    @Override
    public List<MedicationSummaryVo> queryList(MedicationSummaryBo bo) {
        LambdaQueryWrapper<MedicationSummary> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<MedicationSummary> buildQueryWrapper(MedicationSummaryBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<MedicationSummary> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getMedicalRecordNo() != null, MedicationSummary::getMedicalRecordNo, bo.getMedicalRecordNo());
        lqw.eq(bo.getInHospitalDate() != null, MedicationSummary::getInHospitalDate, bo.getInHospitalDate());
        lqw.eq(bo.getOutHospitalDate() != null, MedicationSummary::getOutHospitalDate, bo.getOutHospitalDate());
        lqw.eq(bo.getInHospitalDays() != null, MedicationSummary::getInHospitalDays, bo.getInHospitalDays());
        lqw.eq(StringUtils.isNotBlank(bo.getAdmittingDiagnosisWestern()), MedicationSummary::getAdmittingDiagnosisWestern, bo.getAdmittingDiagnosisWestern());
        lqw.eq(StringUtils.isNotBlank(bo.getReasonableMedicationSummary()), MedicationSummary::getReasonableMedicationSummary, bo.getReasonableMedicationSummary());
        lqw.eq(bo.getPharmaceuticalAmountPercent() != null, MedicationSummary::getPharmaceuticalAmountPercent, bo.getPharmaceuticalAmountPercent());
        lqw.eq(bo.getSelfPharmaceuticalAmountPercent() != null, MedicationSummary::getSelfPharmaceuticalAmountPercent, bo.getSelfPharmaceuticalAmountPercent());
        lqw.eq(StringUtils.isNotBlank(bo.getAntisepsisStrength()), MedicationSummary::getAntisepsisStrength, bo.getAntisepsisStrength());
        lqw.eq(bo.getSpecialAntisepsisPercent() != null, MedicationSummary::getSpecialAntisepsisPercent, bo.getSpecialAntisepsisPercent());
        lqw.eq(StringUtils.isNotBlank(bo.getMicroorganismSample()), MedicationSummary::getMicroorganismSample, bo.getMicroorganismSample());
        lqw.eq(bo.getBaseMedicationAmountPercent() != null, MedicationSummary::getBaseMedicationAmountPercent, bo.getBaseMedicationAmountPercent());
        lqw.eq(StringUtils.isNotBlank(bo.getBaseMedicationNumCondition()), MedicationSummary::getBaseMedicationNumCondition, bo.getBaseMedicationNumCondition());
        lqw.eq(bo.getPurchaseAmountPercent() != null, MedicationSummary::getPurchaseAmountPercent, bo.getPurchaseAmountPercent());
        lqw.eq(bo.getTraditionalPillsAmountPercent() != null, MedicationSummary::getTraditionalPillsAmountPercent, bo.getTraditionalPillsAmountPercent());
        lqw.eq(bo.getTraditionalDrinkAmountPercent() != null, MedicationSummary::getTraditionalDrinkAmountPercent, bo.getTraditionalDrinkAmountPercent());
        lqw.eq(bo.getTraditionalThisAmountPercent() != null, MedicationSummary::getTraditionalThisAmountPercent, bo.getTraditionalThisAmountPercent());
        lqw.eq(bo.getPillsAmountPercent() != null, MedicationSummary::getPillsAmountPercent, bo.getPillsAmountPercent());
        return lqw;
    }

    /**
     * 新增药历小结信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public R<Void> insertByBo(MedicationSummaryBo bo) {
        // 保存药历小结
        MedicationSummary medicationSummary = BeanUtil.toBean(bo, MedicationSummary.class);
        if (ObjectUtil.isNull(medicationSummary.getId())) { // 新增药历小结
            baseMapper.insert(medicationSummary);
        } else { // 更新药历小结
            baseMapper.updateById(medicationSummary);
        }
        // 删除中医诊断和用药章节
        traditionalDiagnosisMapper.delete(new LambdaQueryWrapper<TraditionalDiagnosis>()
            .eq(TraditionalDiagnosis::getMedicalRecordNo, bo.getMedicalRecordNo())
            .eq(TraditionalDiagnosis::getUseType, DictConstants.USE_TYPE_MEDICATION_SUMMARY));
        medicalRecordMapper.delete(new LambdaQueryWrapper<MedicalRecord>()
            .eq(MedicalRecord::getMedicalRecordNo, bo.getMedicalRecordNo())
            //.eq(MedicalRecord::getMedicalType, DictConstants.MEDICAL_TYPE_SUMMARY));
            .in(MedicalRecord::getMedicalType, DictConstants.MEDICAL_TYPE_SUMMARY, DictConstants.MEDICAL_TYPE_SUMMARY_TRADITIONAL));
        // 保存中医诊断集合
        List<TraditionalDiagnosisBo> traditionalDiagnosisBoList = bo.getTraditionalDiagnosisBoList();
        if (ObjectUtil.isNotNull(traditionalDiagnosisBoList) && traditionalDiagnosisBoList.size() > 0) {
            List<TraditionalDiagnosis> traditionalDiagnosisList = BeanUtil.copyToList(traditionalDiagnosisBoList, TraditionalDiagnosis.class);
            traditionalDiagnosisMapper.insertBatch(traditionalDiagnosisList);
        }
        // 保存用药章节
        List<MedicalRecordBo> medicalRecordBoList = bo.getMedicalRecordBoList();
        if (ObjectUtil.isNotNull(medicalRecordBoList) && medicalRecordBoList.size() > 0) {
            List<MedicalRecord> medicalRecordList = BeanUtil.copyToList(medicalRecordBoList, MedicalRecord.class);
            medicalRecordMapper.insertBatch(medicalRecordList);
        }
        // 保存小结饮片
        List<MedicalRecordBo> summaryTraditionalMedicalRecordList = bo.getSummaryTraditionalMedicalRecordList();
        if (ObjectUtil.isNotNull(summaryTraditionalMedicalRecordList) && summaryTraditionalMedicalRecordList.size() > 0) {
            List<MedicalRecord> summaryTraditionalMedicalList = BeanUtil.copyToList(summaryTraditionalMedicalRecordList, MedicalRecord.class);
            medicalRecordMapper.insertBatch(summaryTraditionalMedicalList);
        }
        return R.ok("保存成功");
    }

    /**
     * 修改药历小结信息
     */
    @Override
    public Boolean updateByBo(MedicationSummaryBo bo) {
        MedicationSummary update = BeanUtil.toBean(bo, MedicationSummary.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(MedicationSummary entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除药历小结信息
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 根据病历号查询药历小结信息
     *
     * @param medicalRecordNo 病历号
     * @return
     */
    @Override
    public MedicationSummaryVo queryByMedicalRecordNo(Integer medicalRecordNo) {
        // 创建药历小结视图对象
        MedicationSummaryVo medicationSummaryVo = new MedicationSummaryVo();
        // 查询药历小结信息
        MedicationSummary medicationSummary = baseMapper.selectOne(new LambdaQueryWrapper<MedicationSummary>()
            .eq(MedicationSummary::getMedicalRecordNo, medicalRecordNo));
        if (ObjectUtil.isNotNull(medicationSummary)) {
            medicationSummaryVo = BeanUtil.toBean(medicationSummary, MedicationSummaryVo.class);
        }
        // 西医出院诊断
        if (StringUtils.isBlank(medicationSummaryVo.getAdmittingDiagnosisWestern())) {
            // 从his诊断信息表中查询西医入院诊断
            List<HisAdmittingDiagInfoVo> westDiagList = diagInfoMapper.selectVoList(new LambdaQueryWrapper<HisAdmittingDiagInfo>()
                .eq(HisAdmittingDiagInfo::getMedicalRecordNo, medicalRecordNo)
                .eq(HisAdmittingDiagInfo::getDiagType, DictConstants.DIAG_TYPE_OUT)
                .eq(HisAdmittingDiagInfo::getDiagCat, "西医"));
            if (westDiagList.size() > 0) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < westDiagList.size(); i++) {
                    if (i == westDiagList.size() - 1) {
                        sb.append((i + 1) + "、" + westDiagList.get(i).getDiagDesc());
                        break;
                    }
                    sb.append((i + 1) + "、" + westDiagList.get(i).getDiagDesc() + "；");
                }
                medicationSummaryVo.setAdmittingDiagnosisWestern(sb.toString());
            }
        }
        // 查询中医诊断集合
        List<TraditionalDiagnosisVo> traditionalDiagnosisVoList = traditionalDiagnosisMapper.selectVoList(new LambdaQueryWrapper<TraditionalDiagnosis>()
            .eq(TraditionalDiagnosis::getMedicalRecordNo, medicalRecordNo)
            .eq(TraditionalDiagnosis::getUseType, DictConstants.USE_TYPE_MEDICATION_SUMMARY));
        // 查询HIS诊断信息表中的中医入院诊断信息
        if (traditionalDiagnosisVoList.size() == 0) {
            List<HisAdmittingDiagInfoVo> westDiagList = diagInfoMapper.selectVoList(new LambdaQueryWrapper<HisAdmittingDiagInfo>()
                .eq(HisAdmittingDiagInfo::getMedicalRecordNo, medicalRecordNo)
                .eq(HisAdmittingDiagInfo::getDiagType, DictConstants.DIAG_TYPE_OUT)
                .in(HisAdmittingDiagInfo::getDiagCat, "中医", "证型"));
            String illnessName = null;
            for (HisAdmittingDiagInfoVo hisAdmittingDiagInfoVo :
                westDiagList) {
                if ("中医".equals(hisAdmittingDiagInfoVo.getDiagCat())) {
                    illnessName = hisAdmittingDiagInfoVo.getDiagDesc();
                } else {
                    TraditionalDiagnosisVo traditionalDiagnosisVo = new TraditionalDiagnosisVo();
                    traditionalDiagnosisVo.setMedicalRecordNo(medicalRecordNo);
                    traditionalDiagnosisVo.setIllnessName(illnessName);
                    traditionalDiagnosisVo.setPatternOfSyndrome(hisAdmittingDiagInfoVo.getDiagDesc());
                    traditionalDiagnosisVo.setUseType(DictConstants.USE_TYPE_MEDICATION_SUMMARY);
                    traditionalDiagnosisVoList.add(traditionalDiagnosisVo);
                }
            }
        }
        medicationSummaryVo.setTraditionalDiagnosisVoList(traditionalDiagnosisVoList);
        // 查询用药章节集合
        List<MedicalRecordVo> medicalRecordVoList = medicalRecordMapper.selectVoList(new LambdaQueryWrapper<MedicalRecord>()
            .eq(MedicalRecord::getMedicalRecordNo, medicalRecordNo)
            .eq(MedicalRecord::getMedicalType, DictConstants.MEDICAL_TYPE_SUMMARY));
        medicationSummaryVo.setMedicalRecordVoList(medicalRecordVoList);
        // 查询小结饮片结合
        List<MedicalRecordVo> traditionalMedicalRecordList = medicalRecordMapper.selectVoList(new LambdaQueryWrapper<MedicalRecord>()
            .eq(MedicalRecord::getMedicalRecordNo, medicalRecordNo)
            .eq(MedicalRecord::getMedicalType, DictConstants.MEDICAL_TYPE_SUMMARY_TRADITIONAL));
        medicationSummaryVo.setSummaryTraditionalMedicalRecordList(traditionalMedicalRecordList);
        return medicationSummaryVo;
    }

    /**
     * 下载药学监护小结
     *
     * @param response
     * @param medicalRecordNo 药历号
     */
    @Override
    public void exportPharmaceuticalCareSummary(HttpServletResponse response, Integer medicalRecordNo) {
        // 列表渲染插件
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure configure = Configure.builder()
            .bind("traditionalDiagnosisList", policy)
            .bind("medicalRecordList", policy)
            .bind("summaryTraditionalList", policy)
            .build();
        Map<String, Object> datas = getPharmaceuticalCareSummaryMap(medicalRecordNo);
        try {
            // 读取模板渲染数据
            ResourceLoader resourceLoader = new DefaultResourceLoader();
            Resource resource = resourceLoader.getResource("classpath:template/medication_summary.docx");
            InputStream inputStream = null;
            inputStream = resource.getInputStream();
            XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(datas);
            // 查询患者基本信息
            String patientName = null;
            PatientBaseInfo patientBaseInfo = patientBaseInfoMapper.selectOne(new LambdaQueryWrapper<PatientBaseInfo>()
                .eq(PatientBaseInfo::getMedicalRecordNo, medicalRecordNo)
                .select(PatientBaseInfo::getPatientName));
            if (ObjectUtil.isNotNull(patientBaseInfo)) {
                patientName = patientBaseInfo.getPatientName();
            }
            // 下载word文档
            PoiTlUtils.createOutPusStream(response, template, medicalRecordNo + "-" + patientName + "-药学监护小结");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取药历小结map数据
     *
     * @param medicalRecordNo 药历号
     * @return
     */
    @Override
    public Map<String, Object> getPharmaceuticalCareSummaryMap(Integer medicalRecordNo) {
        // 映射数据Map
        Map<String, Object> datas = new HashMap<String, Object>();
        // 查询药历小结信息
        MedicationSummaryVo medicationSummaryVo = baseMapper.selectVoOne(new LambdaQueryWrapper<MedicationSummary>()
            .eq(MedicationSummary::getMedicalRecordNo, medicalRecordNo));
        if (ObjectUtil.isNotNull(medicationSummaryVo)) {
            if (StringUtils.isBlank(medicationSummaryVo.getSigner()))
                medicationSummaryVo.setSigner("佚名");
            datas.put("medicationSummaryVo", medicationSummaryVo);
        }
        // 初始化列表对象
        traditionalDiagnosisList = new ArrayList<>();
        medicalRecordList = new ArrayList<>();
        traditionalMedicalList = new ArrayList<>();
        // 查询中医出院诊断信息
        List<TraditionalDiagnosisVo> traditionalDiagnosisVoList = traditionalDiagnosisMapper.selectVoList(new LambdaQueryWrapper<TraditionalDiagnosis>()
            .eq(TraditionalDiagnosis::getMedicalRecordNo, medicalRecordNo)
            .eq(TraditionalDiagnosis::getUseType, DictConstants.USE_TYPE_MEDICATION_SUMMARY));
        if (ObjectUtil.isNotNull(traditionalDiagnosisVoList) && traditionalDiagnosisVoList.size() > 0) {
            traditionalDiagnosisVoList.stream().forEach(traditionalDiagnosisVo -> {
                // 封装数据到Map
                Map<String, Object> map = new HashMap<>();
                map.put("illnessName", traditionalDiagnosisVo.getIllnessName());
                map.put("patternOfSyndrome", traditionalDiagnosisVo.getPatternOfSyndrome());
                traditionalDiagnosisList.add(map);
            });
            datas.put("traditionalDiagnosisList", traditionalDiagnosisList);
        }
        // 查询住院期间治疗药物汇总信息
        List<MedicalRecordVo> medicalRecordVoList = medicalRecordMapper.selectVoList(new LambdaQueryWrapper<MedicalRecord>()
            .eq(MedicalRecord::getMedicalRecordNo, medicalRecordNo)
            .eq(MedicalRecord::getMedicalType, DictConstants.MEDICAL_TYPE_SUMMARY));
        if (ObjectUtil.isNotNull(medicalRecordVoList) && medicalRecordVoList.size() > 0) {
            medicalRecordVoList.stream().forEach(medicalRecordVo -> {
                // 封装数据到Map
                Map<String, Object> map = new HashMap<>();
                map.put("purpose", medicalRecordVo.getPurpose());
                map.put("pillsName", medicalRecordVo.getPillsName());
                map.put("amountPer", medicalRecordVo.getAmountPer());
                map.put("pillsUsage", medicalRecordVo.getPillsUsage());
                map.put("frequency", medicalRecordVo.getFrequency());
                if ("Y".equals(medicalRecordVo.getIsContinue())) {
                    map.put("isContinue", "是");
                } else if ("N".equals(medicalRecordVo.getIsContinue())) {
                    map.put("isContinue", "否");
                } else {
                    map.put("isContinue", "");
                }
                LocalDateTime beginDateTime = medicalRecordVo.getBeginDate();
                LocalDateTime endDateTime = medicalRecordVo.getEndDate();
                String beginDate = "";
                String endDate = "";
                if (ObjectUtil.isNotNull(beginDateTime))
                    beginDate = beginDateTime.toLocalDate().toString();
                if (ObjectUtil.isNotNull(endDateTime))
                    endDate = endDateTime.toLocalDate().toString();
                map.put("date", beginDate + "到" + endDate);
                medicalRecordList.add(map);
            });
            datas.put("medicalRecordList", medicalRecordList);
        }
        // 查询住院期间治疗药物中药饮片汇总信息
        List<MedicalRecordVo> traditionalMedicalVoList = medicalRecordMapper.selectVoList(new LambdaQueryWrapper<MedicalRecord>()
            .eq(MedicalRecord::getMedicalRecordNo, medicalRecordNo)
            .eq(MedicalRecord::getMedicalType, DictConstants.MEDICAL_TYPE_SUMMARY_TRADITIONAL));
        traditionalMedicalVoList.stream().forEach(medicalRecordVo -> {
            Map<String, Object> map = new HashMap<>();
            map.put("purpose", medicalRecordVo.getPurpose());
            map.put("pillsName", medicalRecordVo.getPillsName());
            map.put("pillsUsage", medicalRecordVo.getPillsUsage());
            String beginDate = "";
            String endDate = "";
            if (ObjectUtil.isNotNull(medicalRecordVo.getBeginDate())) {
                map.put("beginDate", medicalRecordVo.getBeginDate().toLocalDate());
                beginDate = medicalRecordVo.getBeginDate().toLocalDate().toString();
            }
            if (ObjectUtil.isNotNull(medicalRecordVo.getEndDate())) {
                map.put("endDateStr", medicalRecordVo.getEndDate().toLocalDate());
                endDate = medicalRecordVo.getEndDate().toLocalDate().toString();
            }
            if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate)) {
                map.put("date", beginDate + "到" + endDate);
            } else {
                map.put("date", "");
            }
            traditionalMedicalList.add(map);
        });
        datas.put("summaryTraditionalList", traditionalMedicalList);
        return datas;
    }

    /**
     * 完成并存档药历
     *
     * @param medicalRecordNo 流水号
     * @return
     */
    @Override
    public R<Void> setSubmitState(Integer medicalRecordNo) {
        try {
            // 查询药历小结信息
            MedicationSummaryVo medicationSummaryVo = baseMapper.selectVoOne(new LambdaQueryWrapper<MedicationSummary>()
                .eq(MedicationSummary::getMedicalRecordNo, medicalRecordNo));
            if (ObjectUtil.isNull(medicationSummaryVo)) {
                return R.fail("药历不存在，请先保存药历！");
            }
            // 更新完成状态
            medicationSummaryVo.setSummaryState("1");
            return baseMapper.updateById(BeanUtil.toBean(medicationSummaryVo, MedicationSummary.class)) > 0 ? R.ok("提交成功") : R.fail("提交失败");
        } catch (Exception e) {
            return R.fail("提交失败");
        }
    }
}
